package io.adrainty.bolee.insurance.handler.impl;

import cn.hutool.core.collection.CollUtil;
import io.adrainty.bolee.framework.commons.basic.ResponseCode;
import io.adrainty.bolee.framework.commons.exception.AppException;
import io.adrainty.bolee.framework.commons.utils.JsonUtil;
import io.adrainty.bolee.insurance.constants.InsuranceConstant;
import io.adrainty.bolee.insurance.handler.AbstractInsuranceHandler;
import io.adrainty.bolee.insurance.models.aggregate.EarningResultDTO;
import io.adrainty.bolee.insurance.models.aggregate.InsuranceProcessDTO;
import io.adrainty.bolee.insurance.models.aggregate.WarrantyTimeDTO;
import io.adrainty.bolee.insurance.models.entity.*;
import io.adrainty.bolee.insurance.models.request.DoInsuranceDTO;
import io.adrainty.bolee.insurance.models.valobj.UnderwritingStateEnum;
import io.adrainty.bolee.insurance.models.valobj.WarrantyStateEnum;
import org.apache.commons.lang3.ObjectUtils;

import java.math.BigDecimal;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;

/**
 * 保障类(个险实现)
 *
 * @author AdRainty
 * @version V1.0.0
 * @since 2025/8/24 下午11:10
 */
public abstract class SafeguardInsuranceHandler extends AbstractInsuranceHandler {

    @Override
    public WarrantyEntity doInsure(DoInsuranceDTO doInsuranceDTO) {
        checkInsuranceData(doInsuranceDTO);
        InsuranceProcessDTO insuranceProcessDTO = buildInsureProcessDTO(doInsuranceDTO.getInsuranceId(), doInsuranceDTO.getInsurancePlanId(),
                doInsuranceDTO.getCompanyNo(), doInsuranceDTO.getInsuranceCoefficentIds());
        InsuranceEntity insuranceEntity = insuranceProcessDTO.getInsuranceEntity();
        InsurancePlanEntity insurancePlanEntity = insuranceProcessDTO.getInsurancePlanEntity();
        List<InsuranceCoefficientEntity> insuranceCoefficientList = new ArrayList<>(
                insuranceProcessDTO.getInsuranceCoefficientList());

        // 被投保人信息
        List<CustomerRelationEntity> relationEntities = buildCustomerRelationList(doInsuranceDTO.getCustomerRelationIds());
        CustomerRelationEntity customerRelationEntity = relationEntities.get(0);

        checkInsuranceAge(insuranceEntity, customerRelationEntity);
        checkBaseOnly(insuranceCoefficientList);
        checkRequireCoefficient(insuranceCoefficientList, InsuranceConstant.SAFEGUARD_CHECK_RULE);

        // 投保年龄系数
        ageHandler(insuranceCoefficientList, insuranceEntity.getId(), customerRelationEntity);
        Map<String, InsuranceCoefficientEntity> collect = buildCoefficientMap(insuranceCoefficientList);
        String price = premiumComputeSafeguard(insurancePlanEntity, insuranceCoefficientList);
        doInsuranceDTO.setPrice(new BigDecimal(price));
        // 总周期计算
        Integer periods = doPeriods(collect);
        // 犹豫期截止时间、等待期截止时间、保障截止时间
        WarrantyTimeDTO warrantyTimeDTO = buildTimeSetup(doInsuranceDTO, collect, insuranceEntity);
        CustomerRelationEntity applicant = buildApplicant();
        // 构建保障合同对象
        return WarrantyEntity.builder()
                .insuranceId(insuranceEntity.getId())
                .insuranceName(insuranceEntity.getInsuranceName())
                .insuranceJson(JsonUtil.toJson(insuranceProcessDTO))
                .warrantyNo(String.valueOf(identifierGenerator.nextId(insuranceProcessDTO)))
                .applicantName(applicant.getName())
                .applicantIdentityCard(applicant.getIdentityCard())
                .companyNo(insuranceProcessDTO.getCompanyEntity().getCompanyNo())
                .companyName(insuranceProcessDTO.getCompanyEntity().getCompanyName())
                .safeguardStartTime(warrantyTimeDTO.getSafeguardStartTime())
                .safeguardEndTime(warrantyTimeDTO.getSafeguardEndTime())
                .premium(doInsuranceDTO.getPrice())
                .premiums(doInsuranceDTO.getPrice().multiply(new BigDecimal(periods)))
                .autoWarrantyExtension(getJsonAttribute(collect, InsuranceConstant.AUTO_WARRANTY_EXTENSION).getVal())
                .warrantyState(WarrantyStateEnum.WAIT_PAY)
                .underwritingState(UnderwritingStateEnum.UNDERWRITING_ING)
                .periods(periods)
                .dutyPeriod(0)
                .hesitationTime(warrantyTimeDTO.getHesitationTime())
                .waitTime(warrantyTimeDTO.getWaitTime())
                .grace(insuranceEntity.getGrace())
                .graceUnit(insuranceEntity.getGraceUnit())
                .revival(insuranceEntity.getRevival())
                .revivalUnit(insuranceEntity.getRevivalUnit())
                .periodicUnit(getJsonAttribute(collect, InsuranceConstant.PERIODIC).getVal())
                .customerRelationVOs(relationEntities)
                .build();
    }

    @Override
    public String doPremium(DoInsuranceDTO doInsureVo) {
        checkInsuranceData(doInsureVo);
        InsuranceProcessDTO insuranceProcessDTO = buildInsureProcessDTO(doInsureVo.getInsuranceId(), doInsureVo.getInsurancePlanId(),
                doInsureVo.getCompanyNo(), doInsureVo.getInsuranceCoefficentIds());
        InsuranceEntity insuranceEntity = insuranceProcessDTO.getInsuranceEntity();
        InsurancePlanEntity insurancePlanEntity = insuranceProcessDTO.getInsurancePlanEntity();
        List<InsuranceCoefficientEntity> insuranceCoefficientList = new ArrayList<>(
                insuranceProcessDTO.getInsuranceCoefficientList());

        // 被投保人信息
        List<CustomerRelationEntity> relationEntities = buildCustomerRelationList(doInsureVo.getCustomerRelationIds());
        CustomerRelationEntity customerRelationEntity = relationEntities.get(0);

        checkInsuranceAge(insuranceEntity, customerRelationEntity);
        checkBaseOnly(insuranceCoefficientList);
        checkRequireCoefficient(insuranceCoefficientList, InsuranceConstant.SAFEGUARD_CHECK_RULE);

        // 投保年龄系数
        ageHandler(insuranceCoefficientList, insuranceEntity.getId(), customerRelationEntity);
        return premiumComputeSafeguard(insurancePlanEntity, insuranceCoefficientList);
    }

    @Override
    public EarningResultDTO doEarnings(DoInsuranceDTO doInsuranceDTO) {
        return null;
    }

    /**
     * 计算保费
     *
     * @param insuranceCoefficientList 投保系数项
     * @param insurancePlanEntity      方案信息
     * @return 投保系数项
     */
    protected String premiumComputeSafeguard(InsurancePlanEntity insurancePlanEntity,
                                             List<InsuranceCoefficientEntity> insuranceCoefficientList) {
        // 最终系数合=1+系数A+系数B+系数C+......[不含缴费方式]
        BigDecimal sumScore = insuranceCoefficientList.stream()
                .filter(n -> !InsuranceConstant.PAYMENT.equals(n.getCoefficientKey()))
                .map(n -> ObjectUtils.defaultIfNull(n.getScore(), BigDecimal.ZERO))
                .reduce(BigDecimal.ZERO, BigDecimal::add).add(BigDecimal.ONE);
        // 付款方式
        InsuranceCoefficientEntity payment = insuranceCoefficientList.stream()
                .filter(n -> InsuranceConstant.PAYMENT.equals(n.getCoefficientKey()))
                .findFirst()
                .orElseThrow(() -> new AppException(ResponseCode.INSURANCE_CALCULATE_ERROR, "请选择缴费方式"));
        BigDecimal score = payment.getScore();
        // 最终投保金额= 方案起步价 X 最终系数 X 缴费方式系数
        DecimalFormat decimalFormat = new DecimalFormat("0.00");
        return decimalFormat.format(insurancePlanEntity.getPrice().multiply(sumScore).multiply(score));
    }

    /**
     * 校验数据
     *
     * @param doInsureVo 投保参数
     */
    protected void checkInsuranceData(DoInsuranceDTO doInsureVo) {
        if (CollUtil.isEmpty(doInsureVo.getCustomerRelationIds())) {
            throw new AppException(ResponseCode.INSURANCE_CALCULATE_ERROR, "请选择被保人");
        }
        if (doInsureVo.getCustomerRelationIds().size() > 1) {
            throw new AppException(ResponseCode.INSURANCE_CALCULATE_ERROR, "不支持团险");
        }
        if (Objects.nonNull(doInsureVo.getSafeguardStartTime())) {
            throw new AppException(ResponseCode.INSURANCE_CALCULATE_ERROR, "不支持自定义保单起保时间");
        }
    }

}
